defmodule PlausibleWeb.Live.FunnelSettings do
  @moduledoc """
  LiveView allowing listing, creating and deleting funnels.
  """
  use PlausibleWeb, :live_view

  use Plausible.Funnel

  alias Plausible.{Goals, Funnels}

  def mount(
        _params,
        %{"site_id" => site_id, "domain" => domain},
        socket
      ) do
    socket =
      socket
      |> assign_new(:site, fn %{current_user: current_user} ->
        Plausible.Sites.get_for_user!(current_user, domain,
          roles: [
            :owner,
            :admin,
            :editor,
            :super_admin
          ]
        )
      end)
      |> assign_new(:all_funnels, fn %{site: %{id: ^site_id} = site} ->
        Funnels.list(site)
      end)
      |> assign_new(:goal_count, fn %{site: site} ->
        Goals.count(site)
      end)

    {:ok,
     assign(socket,
       site_team: socket.assigns.site.team,
       domain: domain,
       displayed_funnels: socket.assigns.all_funnels,
       setup_funnel?: false,
       filter_text: "",
       funnel_id: nil
     )}
  end

  # Flash sharing with live views within dead views can be done via re-rendering the flash partial.
  # Normally, we'd have to use live_patch which we can't do with views unmounted at the router it seems.
  def render(assigns) do
    ~H"""
    <div id="funnel-settings-main">
      <.flash_messages flash={@flash} />

      <.tile
        docs="funnel-analysis"
        feature_mod={Plausible.Billing.Feature.Funnels}
        feature_toggle?={true}
        show_content?={!Plausible.Billing.Feature.Funnels.opted_out?(@site)}
        site={@site}
        current_user={@current_user}
        current_team={@current_team}
      >
        <:title>
          Funnels
        </:title>
        <:subtitle :if={Enum.count(@all_funnels) > 0}>
          Compose goals into funnels to track user flows and conversion rates.
        </:subtitle>
        <%= if @setup_funnel? do %>
          {live_render(
            @socket,
            PlausibleWeb.Live.FunnelSettings.Form,
            id: "funnels-form",
            session: %{
              "domain" => @domain,
              "funnel_id" => @funnel_id
            }
          )}
        <% end %>
        <div :if={@goal_count >= Funnel.min_steps()}>
          <.live_component
            module={PlausibleWeb.Live.FunnelSettings.List}
            id="funnels-list"
            funnels={@displayed_funnels}
            filter_text={@filter_text}
          />
        </div>

        <div
          :if={@goal_count < Funnel.min_steps()}
          class="flex flex-col items-center justify-center pt-5 pb-6 max-w-md mx-auto"
        >
          <h3 class="text-center text-base font-medium text-gray-900 dark:text-gray-100 leading-7">
            Ready to dig into user flows?
          </h3>
          <p class="text-center text-sm mt-1 text-gray-500 dark:text-gray-400 leading-5 text-pretty">
            Set up a few goals like <.highlighted>Signup</.highlighted>, <.highlighted>Visit /</.highlighted>, or
            <.highlighted>Scroll 50% on /blog/*</.highlighted>
            first, then return here to build your first funnel.
          </p>
          <.button_link
            class="mt-4"
            href={PlausibleWeb.Router.Helpers.site_path(@socket, :settings_goals, @domain)}
          >
            Set up goals →
          </.button_link>
        </div>
      </.tile>
    </div>
    """
  end

  def handle_event("reset-filter-text", _params, socket) do
    {:noreply, assign(socket, filter_text: "", displayed_funnels: socket.assigns.all_funnels)}
  end

  def handle_event("filter", %{"filter-text" => filter_text}, socket) do
    new_list =
      PlausibleWeb.Live.Components.ComboBox.StaticSearch.suggest(
        filter_text,
        socket.assigns.all_funnels,
        to_string: & &1.name
      )

    {:noreply, assign(socket, displayed_funnels: new_list, filter_text: filter_text)}
  end

  def handle_event("add-funnel", _value, socket) do
    {:noreply, assign(socket, setup_funnel?: true)}
  end

  def handle_event("edit-funnel", %{"funnel-id" => id}, socket) do
    {:noreply, assign(socket, setup_funnel?: true, funnel_id: String.to_integer(id))}
  end

  def handle_event("delete-funnel", %{"funnel-id" => id}, socket) do
    site =
      Plausible.Sites.get_for_user!(
        socket.assigns.current_user,
        socket.assigns.domain,
        roles: [:owner, :admin, :editor]
      )

    id = String.to_integer(id)
    :ok = Funnels.delete(site, id)
    socket = put_live_flash(socket, :success, "Funnel deleted successfully")

    {:noreply,
     assign(socket,
       all_funnels: Enum.reject(socket.assigns.all_funnels, &(&1.id == id)),
       displayed_funnels: Enum.reject(socket.assigns.displayed_funnels, &(&1.id == id))
     )}
  end

  def handle_info({:funnel_saved, _funnel}, socket) do
    socket = put_live_flash(socket, :success, "Funnel saved successfully")

    funnels = Funnels.list(socket.assigns.site)

    {:noreply,
     assign(socket,
       setup_funnel?: false,
       all_funnels: funnels,
       funnel_id: nil,
       displayed_funnels: funnels
     )}
  end

  def handle_info(:cancel_setup_funnel, socket) do
    {:noreply, assign(socket, setup_funnel?: false, funnel_id: nil)}
  end

  def handle_info({:feature_toggled, flash_msg, updated_site}, socket) do
    {:noreply, assign(put_flash(socket, :success, flash_msg), site: updated_site)}
  end
end
